<?php

/**

 * Utility class for installing aLinks

 *

 * Copyright (C) 2008  Sean Hickey

 * 

 * This program is free software: you can redistribute it and/or modify

 * it under the terms of the GNU General Public License as published by

 * the Free Software Foundation, either version 3 of the License, or

 * (at your option) any later version.

 *

 * This program is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

 * GNU General Public License for more details.

 *

 * You should have received a copy of the GNU General Public License

 * along with this program.  If not, see <http://www.gnu.org/licenses/>.

 *

 * @author Sean Hickey <sean@headzoo.com>

 * @version $Id: Install.php 429 2008-07-13 20:08:59Z sean $

 * @package Alinks_Install

 */

class Alinks_Install

{

	/**

	 * Array of directory names that must exist

	 *

	 * @var array

	 */

	protected $_dirs = array(

		'factories' 			=> array('needs_writable' => true),

		'includes' 				=> array('needs_writable' => false),

		'includes/Alinks'		=> array('needs_writable' => false),

		'includes/AlinksMenus'	=> array('needs_writable' => false),

		'includes/dojo'			=> array('needs_writable' => false),

		'includes/styles'		=> array('needs_writable' => false),

		'temp' 					=> array('needs_writable' => true),

		'temp/logs' 			=> array('needs_writable' => true),

		'temp/cache' 			=> array('needs_writable' => true)

	);

	

	/**

	 * Instance of wpdb

	 *

	 * @var wpdb

	 */

	protected $_wpdb;

	

	/**

	 * The directory where aLinks is installed

	 *

	 * @var string

	 */

	protected $_install_path;

	

	/**

	 * Constructor

	 *

	 * @param string $install_path The path where aLinks is installed

	 */

	public function __construct($install_path, wpdb $wpdb, $table_prefix)

	{

		$this->_install_path = rtrim($install_path, '/\\');

		$wpdb->alinks_keyphrases 	= $table_prefix . 'alinks_keyphrases';

		$wpdb->alinks_k_options 	= $table_prefix . 'alinks_k_options';

		$wpdb->alinks_settings 		= $table_prefix . 'alinks_settings';

		$this->_wpdb = $wpdb;

	}

	

	/**

	 * Installs aLinks

	 */

	public function install()

	{

		$this->_verifyDirectories();

		$this->_verifyVersion();

		$this->_createTables();

		$this->_convertOptions();

		$this->_convertModuleOptions();

		if (get_option('autolinks_keywords')) {

			try {

			$this->_upgradeLt5();

			} catch (Alinks_Exception $e) {

				add_option('alinks_error', $e->getMessage(), true);

				return;

			}

		}

	}

	

	/**

	 * Verifies that are required directories are installed

	 *

	 * Also makes sure that directories that need write permission are

	 * writable.

	 */

	protected function _verifyDirectories()

	{

		foreach($this->_dirs as $dir => $options) {

			if (!file_exists($this->_install_path . "/$dir")) {

				add_option('alinks_error', 'Deactivating aLinks. The directory ' . $this->_install_path . "/$dir does not exist. Check your installation.", true);

				return;

			}

			if ($options['needs_writable'] && !is_writable($this->_install_path . "/$dir")) {

				add_option('alinks_error', 'Deactivating aLinks. The directory ' . $this->_install_path . "/$dir needs write permissions. Please give the directory write permissions,

				and then activate aLinks again.", true);

				return;

			}

		}

	}

	

	/**

	 * Verifies that the PHP version

	 */

	protected function _verifyVersion()

	{

		if (phpversion() < 5) {

			add_option('alinks_error', 'Deactivating aLinks. You are using PHP version ' . phpversion() . ', but PHP 5 or greater is required.', true);

			return;

		}

	}

	

	/**

	 * Converts the way options were stored in old versions of aLinks

	 */

	protected function _convertOptions()

	{

		if (!($settings = get_option('alinks_settings'))) {

			return;

		}

		

		/**

		 * Settings that are no longer valid in this version

		 */

		$invalid_settings = array(

			'linkimage',

			'targetwindow',

			'newwindow',

			'clicktracking',

			'casesensitive'

		);

		

		/**

		 * @see Alinks_Settings

		 */

		require_once('Alinks/Options.php');

		

		foreach($settings as $key => $value) {

			/**

			 * Some of the option names have changed from previous

			 * versions.

			 */

			switch($key) {

				case 'newwindow':

				case 'targetwindow':

					$key = Alinks_Settings::NEW_WINDOW;

					if (empty($value)) {

						$value = Alinks_Settings::DEFAULT_NEW_WINDOW;

					} else {

						$value = 1;

					}

					break;

				case 'customhtmljs':

					$key = Alinks_Settings::INNER_HTML;

					break;

				case 'cssclass':

					$key = Alinks_Settings::CLASSES;

					break;

			}

			if (in_array($key, $invalid_settings)) {

				continue;

			}

			

			$key = $this->_wpdb->escape($key);

			$value = $this->_wpdb->escape($value);

			$this->_wpdb->query("INSERT INTO " . $this->_wpdb->alinks_settings . " VALUES(null, 'alinks', '$key', '$value')");

		}

		

		delete_option('alinks_settings');

	}

	

	/**

	 * Converts the old module options into factory settings

	 */

	protected function _convertModuleOptions()

	{

		$results = $this->_wpdb->get_results("SELECT * FROM " . $this->_wpdb->options . " WHERE `option_name` LIKE 'alinks_mod_%'", ARRAY_A);

		foreach((array)$results as $result) {

			$factory = substr($result['option_name'], 11);

			if ($factory == 'general') {

				$factory = 'default';

			} else if ($factory == 'amazon') {

				$factory = 'amazon_basic';

			}

			

			$factory = $this->_wpdb->escape($factory);

			$values = unserialize($result['option_value']);

			foreach($values as $key => $value) {

				$key = $this->_wpdb->escape($key);

				$value = $this->_wpdb->escape($value);

				$this->_wpdb->query("INSERT INTO " . $this->_wpdb->alinks_settings . " VALUES(null, '$factory', '$key', '$value')");

			}

			

			delete_option($result['option_name']);

		}

	}

	

	/**

	 * Creates the aLinks database tables

	 */

	protected function _createTables()

	{

		if (!file_exists(ABSPATH . 'wp-admin/upgrade-functions.php')) {

			add_option('alinks_error', 'Could not find the file ' . ABSPATH . 'wp-admin/upgrade-functions.php. Check your WordPress installation, and try to activate aLinks again.', true);

			return;

		}

		require_once(ABSPATH . 'wp-admin/upgrade-functions.php');

		

		/**

		 * Create the database table for the keyphrase options

		 */

		if (!$this->_wpdb->get_results('DESCRIBE ' . $this->_wpdb->alinks_k_options)) {

			$sql = "

			CREATE TABLE `" . $this->_wpdb->alinks_k_options . "` (

			`keyphrase_hash` varchar(74) NOT NULL,

			`key` varchar(30) NOT NULL,

			`value` text NOT NULL,

			UNIQUE KEY `keyphrase_hash` (`keyphrase_hash`,`key`)

			) ENGINE=MyISAM DEFAULT CHARSET=utf8";

			dbDelta($sql);

		}

		

		/**

		 * Gee.. dbDelta doesn't return any value indicating success or

		 * not. What a PITA.

		 */

		if (!$this->_wpdb->get_results('DESCRIBE ' . $this->_wpdb->alinks_k_options)) {

			add_option('alinks_error', 'Failed to create the alinks_k_options database table', true);

			return;

		}

		

		/**

		 * Create the database table for the settings

		 */

		if (!$this->_wpdb->get_results('DESCRIBE ' . $this->_wpdb->alinks_settings)) {

			$sql = "

			CREATE TABLE `" . $this->_wpdb->alinks_settings . "` (

			`id` int(10) unsigned NOT NULL auto_increment,

			`factory` varchar(60) NOT NULL,

			`key` varchar(30) NOT NULL,

			`value` text NOT NULL,

			PRIMARY KEY  (`id`),

			UNIQUE KEY `factory` (`factory`,`key`)

			) ENGINE=MyISAM  DEFAULT CHARSET=utf8";

			dbDelta($sql);

		}

		

		/**

		 * Did I mention that dbDelta doesn't return any meaningful value?

		 */

		if (!$this->_wpdb->get_results('DESCRIBE ' . $this->_wpdb->alinks_settings)) {

			$this->_wpdb->query('DROP TABLE ' . $this->_wpdb->alinks_k_options);

			add_option('alinks_error', 'Failed to create the alinks_settings database table', true);

			return;

		}

		

		/**

		 * Create the keyphrases table

		 */

		if (!$this->_wpdb->get_results('DESCRIBE `' . $this->_wpdb->alinks_keyphrases . '`')) {

			$sql = "

			CREATE TABLE `" . $this->_wpdb->alinks_keyphrases . "` (

			`phrase` varchar(250) NOT NULL,

			`description` text,

			`factory` varchar(60) character set latin1 collate latin1_general_ci NOT NULL,

			`created` datetime NOT NULL,

			`hash` varchar(74) character set latin1 collate latin1_general_ci NOT NULL,

			UNIQUE KEY `hash` (`hash`),

			KEY `phrase` (`phrase`)

			) ENGINE=MyISAM DEFAULT CHARSET=utf8;";

			dbDelta($sql);

			

		/**

		 * If the keyphrases table already existed, check to see if it's from an

		 * old installation of aLinks. If it is, the table needs to be updated.

		 */

		} else if ($this->_wpdb->get_results('DESCRIBE `' . $this->_wpdb->alinks_keyphrases . '` `module`')) {

			try {

				$this->_definesToSettings();

			} catch (Alinks_Exception $e) {

				$this->_wpdb->query('DROP TABLE ' . $this->_wpdb->alinks_k_options);

				$this->_wpdb->query('DROP TABLE ' . $this->_wpdb->alinks_settings);

				$this->_wpdb->query('DROP TABLE ' . $this->_wpdb->alinks_keyphrases);

				add_option('alinks_error', $e->getMessage(), true);

				return;

			}



			$this->_wpdb->query('ALTER TABLE `' . $this->_wpdb->alinks_keyphrases . '` DROP `defines`');

			$this->_wpdb->query('ALTER TABLE `' . $this->_wpdb->alinks_keyphrases . '` CHANGE `module` `factory` VARCHAR(60) NOT NULL');

			$this->_wpdb->query('ALTER TABLE `' . $this->_wpdb->alinks_keyphrases . '` DROP `id`');

			$this->_wpdb->query('ALTER TABLE `' . $this->_wpdb->alinks_keyphrases . '` CHANGE `keyphrase` `phrase` VARCHAR(250) NOT NULL');

			$this->_wpdb->query('ALTER TABLE `' . $this->_wpdb->alinks_keyphrases . '` CHANGE `hash` `hash` VARCHAR(74) NOT NULL');

			$this->_wpdb->query('ALTER TABLE `' . $this->_wpdb->alinks_keyphrases . '` ADD UNIQUE (`hash`)');

			

			$this->_wpdb->query('UPDATE `' . $this->_wpdb->alinks_keyphrases . "` SET `factory` = 'default' WHERE `factory` = 'general'");

			$this->_wpdb->query('UPDATE `' . $this->_wpdb->alinks_keyphrases . "` SET `factory` = 'amazon_basic' WHERE `factory` = 'amazon'");

		}

		

		/**

		 * Did we actually manage to create the alinks_keyphrases table, or alter it?

		 */

		if (!$this->_wpdb->get_results('DESCRIBE `' . $this->_wpdb->alinks_keyphrases . '` `factory`')) {

			$this->_wpdb->query('DROP TABLE ' . $this->_wpdb->alinks_k_options);

			$this->_wpdb->query('DROP TABLE ' . $this->_wpdb->alinks_settings);

			add_option('alinks_error', 'Failed to create or alter the alinks_keyphrases table', true);

			return;

		}

		

		/**

		 * Add a single keyphrase to get them started

		 */

		$this->_wpdb->query("INSERT INTO `" . $this->_wpdb->alinks_keyphrases . "` VALUES ('aLinks', 'A fantastic WordPress plugin!', 'default', '2008-06-22 14:27:21', 'default-2361d7c713915a08d658ac73ff007fa0-2361d7c713915a08d658ac73ff007fa0');");

		$this->_wpdb->query("INSERT INTO `" . $this->_wpdb->alinks_k_options . "` VALUES ('default-2361d7c713915a08d658ac73ff007fa0-2361d7c713915a08d658ac73ff007fa0', 'url', 'http://alinks.headzoo.com');");

	}

	

	/**

	 * Converts the "defines" from previous versions

	 *

	 * @throws Alinks_Exception

	 */

	protected function _definesToSettings()

	{

		$results = $this->_wpdb->get_results('SELECT hash, defines, module FROM `' . $this->_wpdb->alinks_keyphrases . '`', ARRAY_A);

		foreach($results as $result) {

			$defines = @unserialize($result['defines']);

			if (false === $defines) {

				continue;

			}

			

			foreach($defines as $key => $value) {

				$hash 	= $this->_wpdb->escape($result['hash']);

				$key 	= $this->_wpdb->escape($key);

				$value 	= $this->_wpdb->escape($value);

				$sql 	= "INSERT INTO " . $this->_wpdb->alinks_k_options . " VALUES('$hash', '$key', '$value')";

				if (1 != $this->_wpdb->query($sql)) {

					/**

					 * @see Alinks_Exception

					 */

					require_once('Alinks/Exception.php');

					throw new Alinks_Exception("Error while converting $key/$value into keyphrase options");

				}

			}

		}

	}

	

	/**

	 * Upgrades aLinks from versions .5 or less

	 *

	 * This is back when aLinks was named Auto Links. I'd be shocked if

	 * anyone was still using it.

	 *

	 * @return bool

	 * @throws Alinks_Upgrade_Exception

	 */

	protected function _upgradeLt5()

	{

		$general = get_option('autolinks_keywords');

		$amazon = get_option('autolinks_amazonkeywords');

		$this->_createTables();

		

		/**

		 * @see Alinks_Keyphrase

		 */

		require_once('Alinks/Keyphrase.php');

		

		if (!empty($general)) {

			foreach ($general as $keyword => $url) {

				$k = new Alinks_Keyphrase('general');

				$k->setPhrase($keyword);

				

				$phrase 		= $this->_wpdb->escape($k->getPhrase());

				$description 	= $this->_wpdb->escape($k->getDescription());

				$factory 		= $this->_wpdb->escape($k->getFactory());

				$created 		= date('Y-m-d H:i:s', $k->getCreated());

				$hash 			= $this->_wpdb->escape($k->getHash());

				$url 			= $this->_wpdb->escape($url);

				

				$sql = "INSERT INTO " . $this->_wpdb->alinks_keyphrases . "

				VALUES ('$phrase', '$description', '$factory', '$created', '$hash')";

				if (1 != $this->_wpdb->query($sql)) {

					/**

					 * @see Alinks_Exception

					 */

					require_once('Alinks/Exception.php');

					throw new Alinks_Exception('Failed to create General keyphrase $phrase from .5 branch');

				}

				

				$sql = "INSERT INTO " . $this->_wpdb->alinks_k_options . "

				('$hash', 'url', '$url')";

				if (1 != $this->_wpdb->query($sql)) {

					/**

					 * @see Alinks_Exception

					 */

					require_once('Alinks/Exception.php');

					throw new Alinks_Exception('Failed to insert URL for keyphrase $phrase from .5 branch');

				}

				

			}

			

			delete_option('autolinks_keywords');

		}

		

		if (!empty($amazon)) {

			foreach ($amazon as $keyword => $producttype) {

				$k = new Alinks_Keyphrase('amazon_basic');

				$k->setPhrase($keyword);

				

				$phrase 		= $this->_wpdb->escape($k->getPhrase());

				$description 	= $this->_wpdb->escape($k->getDescription());

				$factory 		= $this->_wpdb->escape($k->getFactory());

				$created 		= date('Y-m-d H:i:s', $k->getCreated());

				$hash 			= $this->_wpdb->escape($k->getHash());

				$producttype 	= $this->_wpdb->escape($producttype);

				

				$sql = "INSERT INTO " . $this->_wpdb->alinks_keyphrases . "

				VALUES ('$phrase', '$description', '$factory', '$created', '$hash')";

				if (1 != $this->_wpdb->query($sql)) {

					/**

					 * @see Alinks_Exception

					 */

					require_once('Alinks/Exception.php');

					throw new Alinks_Exception('Failed to create Amazon Basic keyphrase $phrase from .5 branch');

				}

				

				$sql = "INSERT INTO " . $this->_wpdb->alinks_k_options . "

				('$hash', 'product_type', '$producttype')";

				if (1 != $this->_wpdb->query($sql)) {

					/**

					 * @see Alinks_Exception

					 */

					require_once('Alinks/Exception.php');

					throw new Alinks_Exception('Failed to insert product type for keyphrase $phrase from .5 branch');

				}

				$sql = "INSERT INTO " . $this->_wpdb->alinks_k_options . "

				('$hash', 'search_term', '$phrase')";

				if (1 != $this->_wpdb->query($sql)) {

					/**

					 * @see Alinks_Exception

					 */

					require_once('Alinks/Exception.php');

					throw new Alinks_Exception('Failed to insert search term for keyphrase $phrase from .5 branch');

				}

			}

			

			delete_option('autolinks_amazonkeywords');

		}

		

		return true;

	}

}

